package render

import (
	"bytes"
	"github.com/BurntSushi/toml"
	log "github.com/cihub/seelog"
	"github.com/noirbizarre/gonja"
	"io"
	"os"
	"path"
	"path/filepath"
	"strings"
	"wrench/config"
)

type ConfigRenders config.Render

func Render(cliConf *config.HostList, varFile string, templateFile string) (renderFile string, renderErr error) {
	var configMap = make(map[string]interface{})
	defer log.Flush()

	_, configfileNameTmp := filepath.Split(templateFile)

	var filenameBuffer bytes.Buffer
	uuid, _ := os.ReadFile("/proc/sys/kernel/random/uuid")
	filenameBuffer.WriteString(config.TddhHome + ".cache/" + config.GlobalTimestamp + "/" + string(uuid) + "_" + configfileNameTmp + "_" + cliConf.SshIp)

	if !checkFileIsExist(filenameBuffer.String()) {
		if mkdirErr := os.MkdirAll(filenameBuffer.String(), os.ModePerm); mkdirErr != nil {
			return "", mkdirErr
		}
	}

	filenameBuffer.WriteString("/" + strings.TrimSuffix(filepath.Base(configfileNameTmp), path.Ext(templateFile)))
	filename := filenameBuffer.String()

	var varBuffer bytes.Buffer
	if fileVar, err := os.ReadFile(varFile); err != nil {
		return "", err
	} else {
		varBuffer.Write(fileVar)
	}

	hostVar, _ := os.ReadFile(config.TddhHome + ".cache/" + "/.hosts.toml")

	varBuffer.Write(hostVar)
	if _, tomlErr := toml.Decode(varBuffer.String(), &configMap); tomlErr != nil {
		return "", tomlErr
	}
	k := cliConf.SshGroup + "." + cliConf.SshIp
	for key, value := range config.HostVars[k].(map[string]string) {
		configMap[key] = value
	}

	f, openErr := os.OpenFile(filename, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
	defer func(f *os.File) {
		err := f.Close()
		if err != nil {
			_ = log.Warn("[renter] localhost", " close file: ", f.Name(), " ", err.Error())
		}
	}(f)
	if openErr != nil {
		return "", openErr
	}

	tplExample := gonja.Must(gonja.FromFile(templateFile))
	value, tplErr := tplExample.Execute(configMap)
	if tplErr != nil {
		return "", tplErr

	}
	_, err := io.WriteString(f, value)
	if err != nil {
		return "", err
	}

	return filename, nil

}

func (render *ConfigRenders) Render(cliConf *config.HostList, tName string) (renderFile string, renderErr error) {
	var configMap = make(map[string]interface{}) //解析文件
	defer log.Flush()
	_, configfileNameTmp := filepath.Split(render.Src)

	var filenameBuffer bytes.Buffer
	if render.Dst != "" {
		filenameBuffer.WriteString(render.Dst + "/" + config.GlobalTimestamp + "/" + tName + "_" + cliConf.SshIp)
	} else {
		filenameBuffer.WriteString(config.TddhHome + ".cache/" + config.GlobalTimestamp + "/" + tName + "_" + cliConf.SshIp)
	}

	if !checkFileIsExist(filenameBuffer.String()) {
		if mkdirErr := os.MkdirAll(filenameBuffer.String(), os.ModePerm); mkdirErr != nil {
			return "", mkdirErr
		}
	}

	filenameBuffer.WriteString("/" + strings.TrimSuffix(filepath.Base(configfileNameTmp), path.Ext(render.Src)))
	filename := filenameBuffer.String()

	var varBuffer bytes.Buffer
	if fileVar, err := os.ReadFile(render.Temp); err != nil {
		return "", err
	} else {
		varBuffer.Write(fileVar)
	}

	hostVar, _ := os.ReadFile(config.TddhHome + ".cache/" + "/.hosts.toml")

	varBuffer.Write(hostVar)
	if _, tomlErr := toml.Decode(varBuffer.String(), &configMap); tomlErr != nil {
		return "", tomlErr
	}
	k := cliConf.SshGroup + "." + cliConf.SshIp
	for key, value := range config.HostVars[k].(map[string]string) {
		configMap[key] = value
	}

	f, openErr := os.OpenFile(filename, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
	defer func(f *os.File) {
		err := f.Close()
		if err != nil {
			_ = log.Warn("[renter] ", " close file: ", f.Name(), " ", err.Error())
		}
	}(f)
	if openErr != nil {
		return "", openErr
	}

	tplExample := gonja.Must(gonja.FromFile(render.Src))
	value, tplErr := tplExample.Execute(configMap)
	_, err := io.WriteString(f, value)
	if err != nil {
		return "", err
	}
	if tplErr != nil {
		return "", tplErr

	}
	return filename, nil

}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func checkFileIsExist(filename string) bool {
	var exist = true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		exist = false
	}
	return exist
}

func RawWriter(w io.Writer, b []byte) {
	_, err := w.Write(b)
	if err != nil {
		return
	}
}
